package org.zpmis.api.business;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zpmis.common.base.AdminLoginUser;
import org.zpmis.common.base.BaseWebService;
import org.zpmis.common.constant.UserConstants;
import org.zpmis.common.exception.BusinessException;
import org.zpmis.common.result.ResultCode;
import org.zpmis.common.utils.RedisUtil;
import org.zpmis.common.utils.StringUtil;
import org.zpmis.domain.role.model.*;
import org.zpmis.domain.role.qo.*;
import org.zpmis.domain.role.service.*;
import org.zpmis.domain.role.vo.AllSysRoleVo;
import org.zpmis.domain.role.vo.SysPermissionListVo;
import org.zpmis.domain.role.vo.SysRoleListVo;
import org.zpmis.domain.user.model.SysUser;
import org.zpmis.domain.user.service.SysUserService;
import org.zpmis.domain.user.vo.AllSysUserVo;
import tk.mybatis.mapper.entity.Condition;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created with CodeGenerator
 * Description:
 * @author  Yang
 * Date: 2021-5-31
 * Time: 14:00:27
 */
@Service
@Slf4j
public class SysRoleWebService extends BaseWebService {
     @Reference
     private SysRoleService sysRoleService;

     @Reference
     private SysUserService sysUserService;

     @Reference
     private SysPermissionService sysPermissionService;

     @Reference
     private SysUserRoleRelationService sysUserRoleRelationService;

     @Reference
     private SysRoleMenuRelationService sysRoleMenuRelationService;

     @Reference
     private SysRolePermissionRelationService sysRolePermissionRelationService;

     @Reference
     private SysMenuService sysMenuService;


    /**
     * 获取所有用户角色 用户新增修改下拉使用
     * @return
     */
    public List<AllSysRoleVo> allSysRole() throws Exception{
        Condition condition = new Condition(SysRole.class);
        condition.createCriteria()
                .andEqualTo("isDeleted",0);
        List<SysRole> sysRoleList = sysRoleService.findByCondition(condition);
        List<AllSysRoleVo> resultList = sysRoleList.stream().map(AllSysRoleVo::new).collect(Collectors.toList());
        return resultList;
    }

    /**
     * 新增角色
     * @param addSysRoleQo
     * @throws BusinessException
     * @throws Exception
     */
    public void addSysRole(AddSysRoleQo addSysRoleQo) throws BusinessException,Exception{
        //获取当前登录用户
        AdminLoginUser adminLoginUser = super.getAdminLoginUser();
        if(adminLoginUser == null){
            throw new BusinessException(ResultCode.USER_NOT_LOGIN);
        }
        sysRoleService.save(
            SysRole.builder()
                    .roleName(addSysRoleQo.getRoleName())
                    .roleDescription(addSysRoleQo.getRoleDescription())
                    .createTime(Instant.now().toEpochMilli())
                    .createUser(adminLoginUser.getId())
                    .isDeleted(false)
                    .build()
        );
    }

    /**
     * 修改角色信息
     * @param editSysRoleQo
     * @throws BusinessException
     * @throws Exception
     */
    public void editSysRole(EditSysRoleQo editSysRoleQo) throws BusinessException,Exception{
        Long id = editSysRoleQo.getId();
        SysRole sysRole = sysRoleService.findById(id);
        if(sysRole == null){
            throw new BusinessException(ResultCode.DATA_NOT_FOUND);
        }
        //获取当前登录用户
        AdminLoginUser adminLoginUser = super.getAdminLoginUser();
        if(adminLoginUser == null){
            throw new BusinessException(ResultCode.USER_NOT_LOGIN);
        }
        sysRole.setRoleName(editSysRoleQo.getRoleName());
        sysRole.setRoleDescription(editSysRoleQo.getRoleDescription());
        sysRole.setUpdateTime(Instant.now().toEpochMilli());
        sysRole.setUpdateUser(adminLoginUser.getId());
        sysRoleService.update(sysRole);
    }

    /**
     * 删除角色
     * @param delSysRoleQo
     * @throws BusinessException
     * @throws Exception
     */
    @Transactional
    public void delSysRole(DelSysRoleQo delSysRoleQo) throws BusinessException,Exception{
        Long id = delSysRoleQo.getId();
        SysRole sysRole = sysRoleService.findById(id);
        if(sysRole == null){
            throw new BusinessException(ResultCode.DATA_NOT_FOUND);
        }
        //获取当前登录用户
        AdminLoginUser adminLoginUser = super.getAdminLoginUser();
        if(adminLoginUser == null){
            throw new BusinessException(ResultCode.USER_NOT_LOGIN);
        }
        //判断是否有用户关联
        Map<String, Object> param = new HashMap<>();
        param.put("roleId",id);
        List<SysUserRoleRelation> userRoleRelationList = sysUserRoleRelationService.findByConditionMap(param);
        if(!userRoleRelationList.isEmpty()){
            throw new BusinessException(ResultCode.NO_PERMISSION);
        }
        sysRoleService.update(
            SysRole.builder()
                    .id(id)
                    .updateTime(Instant.now().toEpochMilli())
                    .updateUser(adminLoginUser.getId())
                    .isDeleted(true)
                    .build()
        );
        //删除角色菜单关联
        List<SysRoleMenuRelation> roleMenuRelationList = sysRoleMenuRelationService.findByConditionMap(param);
        if(!roleMenuRelationList.isEmpty()){
            String roleMenuRelationIds = roleMenuRelationList.stream().map(roleMenuRelation -> roleMenuRelation.getId().toString()).collect(Collectors.joining(","));
            sysRoleMenuRelationService.deleteByIds(roleMenuRelationIds);
        }
        //删除角色和权限的关联数据
        List<SysRolePermissionRelation> rolePermissionRelationList = sysRolePermissionRelationService.findByConditionMap(param);
        if(!rolePermissionRelationList.isEmpty()){
            String rolePermissionRelationIds = rolePermissionRelationList.stream().map(rolePermissionRelation -> rolePermissionRelation.getId().toString()).collect(Collectors.joining(","));
            sysRolePermissionRelationService.deleteByIds(rolePermissionRelationIds);
        }
    }

    /**
     * 角色列表查询
     * @param sysRoleListQo
     * @return
     * @throws BusinessException
     * @throws Exception
     */
    public PageInfo sysRoleList(SysRoleListQo sysRoleListQo) throws BusinessException,Exception{
        String roleName = sysRoleListQo.getRoleName();
        Long startTime = sysRoleListQo.getStartTime();
        Long endTime = sysRoleListQo.getEndTime();
        Condition condition = new Condition(SysRole.class);
        Example.Criteria criteria = condition.createCriteria();
        criteria.andEqualTo("isDeleted",0);

        if(StringUtil.isNotEmpty(roleName)){
            criteria.andLike("roleName","%"+roleName+"%");
        }
        if(startTime != null && endTime != null){
            criteria.andGreaterThanOrEqualTo("createTime",startTime);
            criteria.andLessThanOrEqualTo("createTime",endTime);
        }

        if(startTime != null && endTime == null){
            criteria.andGreaterThanOrEqualTo("createTime",startTime);
            criteria.andLessThanOrEqualTo("createTime",Instant.now().toEpochMilli());
        }

        if(startTime == null && endTime != null){
            criteria.andLessThanOrEqualTo("createTime",endTime);
        }
        condition.orderBy("createTime").desc();
        PageHelper.startPage(sysRoleListQo.getPageNum(),sysRoleListQo.getPageSize());
        List<SysRole> sysRoleList = sysRoleService.findByCondition(condition);
        PageInfo pageInfo = new PageInfo<>(sysRoleList);
        //自定义返回结果
        List<SysRoleListVo> resultList = sysRoleList.stream().map(SysRoleListVo::new).collect(Collectors.toList());
        pageInfo.setList(resultList);
        return pageInfo;
    }

    /**
     * 角色分配用户
     * @param roleDistributionUserQo
     * @throws BusinessException
     * @throws Exception
     */
    public void roleDistributionUser(RoleDistributionUserQo roleDistributionUserQo)  throws BusinessException,Exception{
        Long roleId = roleDistributionUserQo.getRoleId();
        List<Long> userIds = roleDistributionUserQo.getUserIdList();
        /**
         * 插入之前 先让该角色所在的用户退出登录
         * 根据角色id使该角色下的用户退出登录
         */
        this.roleLogout(roleId);
        //根据角色id 查询现有用户角色关联表的集合
        Map<String, Object> param = new HashMap<>();
        param.put("roleId",roleId);
        List<SysUserRoleRelation> userRoleRelations = sysUserRoleRelationService.findByConditionMap(param);
        if(!userRoleRelations.isEmpty()){
            //删除查询到的该角色之前关联的用户关联集合关系
            String userRoleIds = userRoleRelations.stream().map(sysUserRoleRelation -> sysUserRoleRelation.getId().toString()).collect(Collectors.joining(","));
            sysUserRoleRelationService.deleteByIds(userRoleIds);
        }
        if(userIds == null || userIds.isEmpty()){
            return ;
        }

        //重新插入本次的角色用户关联数据
        List<SysUserRoleRelation> sysUserRoleList = new ArrayList<>();
        userIds.stream().forEach(userId ->
            sysUserRoleList.add(SysUserRoleRelation.builder()
                    .roleId(roleId)
                    .userId(userId)
                    .build()
            )
        );
        if(!sysUserRoleList.isEmpty()){
            sysUserRoleRelationService.save(sysUserRoleList);
        }
        //被分配的用户也需要重新登录 根据用户id强制退出用户
        super.userIdLogout(userIds);
    }

    /**
     * 角色分配权限
     * @param roleDistributionPermissionQo
     */
    public void roleDistributionPermission(RoleDistributionPermissionQo roleDistributionPermissionQo)  throws BusinessException,Exception{
        Long roleId = roleDistributionPermissionQo.getRoleId();
        List<Long> permissionIdList = roleDistributionPermissionQo.getPermissionIdList();

        //根据角色id 查询现有角色权限关联表的集合
        Map<String, Object> param = new HashMap<>();
        param.put("roleId",roleId);
        List<SysRolePermissionRelation> rolePermissionRelations = sysRolePermissionRelationService.findByConditionMap(param);
        if(!rolePermissionRelations.isEmpty()){
            //删除查询到之前的该角色权限关联数据
            String rolePermissionIds = rolePermissionRelations.stream().map(rolePermissionRelation -> rolePermissionRelation.getId().toString()).collect(Collectors.joining(","));
            sysRolePermissionRelationService.deleteByIds(rolePermissionIds);
        }
        if(permissionIdList == null || permissionIdList.isEmpty()){
            return;
        }
        //重新插入本次的角色权限关联数据
        List<SysRolePermissionRelation> rolePermissionRelationList = new ArrayList<>();
        permissionIdList.stream().forEach(permissionId ->
            rolePermissionRelationList.add(
                    SysRolePermissionRelation.builder()
                    .roleId(roleId)
                    .permissionId(permissionId)
                    .build()
            )
        );
        if(!rolePermissionRelationList.isEmpty()){
            sysRolePermissionRelationService.save(rolePermissionRelationList);
        }
    }

    /**
     * 根据角色id查询该角色下的用户集合
     * @param findUserListByRoleIdQo
     * @return
     * @throws BusinessException
     * @throws Exception
     */
    public List<AllSysUserVo> findSysUserListByRoleId(FindListByRoleIdQo findUserListByRoleIdQo) throws BusinessException,Exception{
        Long id = findUserListByRoleIdQo.getId();
        Condition userRoleCondition = new Condition(SysUserRoleRelation.class);
        userRoleCondition.createCriteria()
                .andEqualTo("roleId",id);
        List<SysUserRoleRelation> sysUserRoleRelationList = sysUserRoleRelationService.findByCondition(userRoleCondition);
        if(sysUserRoleRelationList.isEmpty()){
            return new ArrayList<>();
        }
        String userIds = sysUserRoleRelationList.stream().map(sysUserRoleRelation -> sysUserRoleRelation.getUserId().toString()).collect(Collectors.joining(","));
        List<SysUser> sysUserList = sysUserService.findByIds(userIds);
        List<AllSysUserVo> sysUserVoList = sysUserList.stream().map(AllSysUserVo::new).collect(Collectors.toList());
        return sysUserVoList;
    }

    /**
     * 根据角色id 查询角色拥有的所有权限
     * @param findUserListByRoleIdQo
     * @return
     * @throws BusinessException
     * @throws Exception
     */
    public List<SysPermissionListVo> findPermissionListByRoleId(FindListByRoleIdQo findUserListByRoleIdQo) throws BusinessException,Exception{
        Long id = findUserListByRoleIdQo.getId();
        Condition rolePermissionCondition = new Condition(SysRolePermissionRelation.class);
        rolePermissionCondition.createCriteria()
                .andEqualTo("roleId",id);
        List<SysRolePermissionRelation> rolePermissionRelationList = sysRolePermissionRelationService.findByCondition(rolePermissionCondition);
        if(rolePermissionRelationList.isEmpty()){
            return new ArrayList<>();
        }
        String permissionIds = rolePermissionRelationList.stream().map(rolePermissionRelation -> rolePermissionRelation.getPermissionId().toString()).collect(Collectors.joining(","));
        List<SysPermission> sysPermissionList = sysPermissionService.findByIds(permissionIds);
        List<SysPermissionListVo> permissionListVoList = sysPermissionList.stream().map(SysPermissionListVo::new).collect(Collectors.toList());
        return permissionListVoList;

    }

    /**
     * 角色分配菜单
     * @param roleDistributionMenuQo
     * @throws BusinessException
     * @throws Exception
     */
    @Transactional
    public void roleDistributionMenu(RoleDistributionMenuQo roleDistributionMenuQo) throws BusinessException,Exception{
        Long roleId = roleDistributionMenuQo.getRoleId();
        List<Long> menuIdList = roleDistributionMenuQo.getMenuIdList();

        //根据角色id 查询现有角色菜单关联表的集合
        Map<String, Object> param = new HashMap<>();
        param.put("roleId",roleId);
        List<SysRoleMenuRelation> roleMenuRelationList = sysRoleMenuRelationService.findByConditionMap(param);
        if(!roleMenuRelationList.isEmpty()){
            //删除查询到之前的该角色菜单关联数据
            String roleMenuRelationIds = roleMenuRelationList.stream().map(roleMenuRelation -> roleMenuRelation.getId().toString()).collect(Collectors.joining(","));
            sysRoleMenuRelationService.deleteByIds(roleMenuRelationIds);
        }

        //重新插入本次的角色菜单关联数据
        List<SysRoleMenuRelation> roleMenuRelationAddList = new ArrayList<>();
        menuIdList.stream().forEach(menuId ->
                roleMenuRelationAddList.add(
                        SysRoleMenuRelation.builder()
                                .roleId(roleId)
                                .menuId(menuId)
                                .build()
                )
        );
        if(!roleMenuRelationAddList.isEmpty()){
            sysRoleMenuRelationService.save(roleMenuRelationAddList);
        }

        /**
         * 根据角色id使该角色下的用户退出登录
         */
        this.roleLogout(roleId);
        /**
         * 同步更新对应的 角色权限关联表
         */
        //根据角色id 查询现有角色权限关联表的集合
        List<SysRolePermissionRelation> rolePermissionRelations = sysRolePermissionRelationService.findByConditionMap(param);
        if(!rolePermissionRelations.isEmpty()){
            //删除查询到之前的该角色权限关联数据
            String rolePermissionIds = rolePermissionRelations.stream().map(rolePermissionRelation -> rolePermissionRelation.getId().toString()).collect(Collectors.joining(","));
            sysRolePermissionRelationService.deleteByIds(rolePermissionIds);
        }
        if(menuIdList == null || menuIdList.isEmpty()){
            return;
        }
        //重新插入本次的角色权限关联数据
        //根据菜单id 查询出菜单集合
        Condition menuCondition = new Condition(SysMenu.class);
        menuCondition.createCriteria()
                .andIn("id",menuIdList);
        List<SysMenu> menuList = sysMenuService.findByCondition(menuCondition);
        if(menuList.isEmpty()){
            return;
        }
        //提取菜单的url集合
        List<String> urlList = menuList.stream().map(menu -> menu.getRouterUrl()).collect(Collectors.toList());
        //根据菜单url集合查询出对应的权限
        Condition permissionCondition = new Condition(SysPermission.class);
        permissionCondition.createCriteria()
                .andIn("apiUrl",urlList);
        List<SysPermission> permissionList = sysPermissionService.findByCondition(permissionCondition);
        if(permissionList.isEmpty()){
            return;
        }
        //插入角色权限关联集合
        List<SysRolePermissionRelation> rolePermissionRelationList = new ArrayList<>();
        permissionList.stream().forEach(sysPermission ->
            rolePermissionRelationList.add(
                    SysRolePermissionRelation.builder()
                            .roleId(roleId)
                            .permissionId(sysPermission.getId())
                            .build()
            )
        );
            if(!rolePermissionRelationList.isEmpty()){
                sysRolePermissionRelationService.save(rolePermissionRelationList);
            }
    }

    /**
     * 根据角色 是当前角色下的用户登录失效
     * @param roleId
     */
    private void roleLogout(Long roleId){
        /**
         *  菜单分配完之后 让当前角色下的所有用户登录失效
         */
        Map<String, Object> param = new HashMap<>();
        param.put("roleId",roleId);
        //查询用户角色关联表，查询出该角色下的用户id
        List<SysUserRoleRelation> userRoleRelationList = sysUserRoleRelationService.findByConditionMap(param);
        //获取当前角色下的用户在redis中的tokenKey
        List<String> tokenRedisKeys = userRoleRelationList.stream().map(sysUserRoleRelation -> {
            String format = String.format(UserConstants.ADMIN_USER_INFO_REDIS_KEY, sysUserRoleRelation.getUserId());
            return format;
        }).collect(Collectors.toList());
        //通过存储tokenKey 查询出该角色下的所有用户token
        List<String> infoRedisKeys = tokenRedisKeys.stream().filter(key -> redisUtil.get(key) != null).map(redisKey -> {
            Object o = redisUtil.get(redisKey);
            return String.format(UserConstants.ADMIN_USER_TOKEN_REDIS_KEY, o.toString());
        }).collect(Collectors.toList());
        //获取当前角色下的用户在redis中的detail信息
        List<String> detailRedisKeys = userRoleRelationList.stream().map(sysUserRoleRelation -> {
            String format = String.format(UserConstants.ADMIN_USER_LOGIN_DETAIL_KEY, sysUserRoleRelation.getUserId());
            return format;
        }).collect(Collectors.toList());
        //删除用户存储的tokenKey 和 登录信息的key 促使登录失效
        redisUtil.delKeys(tokenRedisKeys);
        redisUtil.delKeys(infoRedisKeys);
        redisUtil.delKeys(detailRedisKeys);
    }

    /**
     * 根据角色id' 查询当前角色关联的菜单id
     * @param findUserListByRoleIdQo
     * @return
     */
    public List<Long> findSysMenuListByRoleId(FindListByRoleIdQo findUserListByRoleIdQo) {
        Long id = findUserListByRoleIdQo.getId();
        //根据角色id 查询现有角色菜单关联表的集合
        Map<String, Object> param = new HashMap<>();
        param.put("roleId",id);
        List<SysRoleMenuRelation> roleMenuRelationList = sysRoleMenuRelationService.findByConditionMap(param);
        List<Long> list = roleMenuRelationList.stream().map(SysRoleMenuRelation::getMenuId).collect(Collectors.toList());
        return list;
    }
}
